Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughこのプルリクエストは、Discord ボットに RSS フィード監視機能を追加し、複数アプリケーション対応ビルドシステムを構築する変更を実装しています。新規 rss_cron アプリケーション、購読管理コマンド、データモデル更新、安全な RSS 取得ユーティリティ、動的化された Docker・ビルドパイプラインを含みます。 ChangesRSS フィード監視機能
複数アプリケーション対応ビルド・デプロイシステム
Sequence Diagram(s)sequenceDiagram
participant Ready as Ready Handler
participant Fetch as FetchFeed Util
participant DB as Database
participant Repo as RSS Repo
participant Parser as gofeed
participant Discord as Discord API
Ready->>Repo: List RSS Settings
Repo->>DB: Query all settings
DB-->>Repo: Settings array
Repo-->>Ready: Settings array
loop Each RSS Setting
Ready->>Fetch: FetchFeed(url)
alt Fetch Failed
Ready->>DB: IsFailed = true Update
else Fetch Success
Fetch->>Parser: Parse RSS
Parser-->>Fetch: Feed data
Fetch-->>Ready: Feed
Ready->>Ready: Sort items by PublishedParsed
Ready->>Ready: Collect target items by hash
loop Each target item (reversed)
Ready->>Discord: CreateMessage(title, description, link)
Discord-->>Ready: Message created
end
Ready->>Ready: Compute new hash from first item
Ready->>DB: LastItemTitleDescriptionHash, IsFailed = false Update
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 golangci-lint (2.12.2)level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies" Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/go.mod (2)
3-3:⚠️ Potential issue | 🟡 Minorgo.mod の
go 1.24.4は有効だが、Docker の Go バージョンと整合させてください
src/go.modのgo 1.24.4は公式に存在する有効なリリースです- ただし
Dockerfile.main/Dockerfile.rss_cronはgolang:1.26.4-alpine3.24を使用しているため、意図したターゲットランタイムに合わせてgo.modと統一(1.24.xに固定するか、1.26.xへ更新)してください🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/go.mod` at line 3, Update the Go version to be consistent between src/go.mod and your Dockerfiles: change the module directive "go 1.24.4" in src/go.mod to match the Docker images (or update the Dockerfiles to match the module), e.g., set src/go.mod to "go 1.26.4" if you keep golang:1.26.4-alpine3.24 in Dockerfile.main and Dockerfile.rss_cron; ensure the version string in the go directive exactly matches the intended toolchain so builds inside Docker and local `go` behave identically.
20-46:⚠️ Potential issue | 🟠 Major間接依存(RSS側)の既知脆弱性が検出されました(更新必須)
golang.org/x/net v0.49.0(// indirect): GO-2026-5025/5027/5028/5029/5030(固定:v0.55.0)github.com/jackc/pgx/v5 v5.8.0(// indirect): GO-2026-4771/4772(固定:v5.9.0)- 標準ライブラリ(Go 1.26.3):
net/textproto/mime/crypto/x509(固定:go1.26.4。Goツールチェーン更新が必要)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/go.mod` around lines 20 - 46, The go.mod contains indirect dependencies with known vulnerabilities; update the versions and toolchain: bump golang.org/x/net from v0.49.0 to v0.55.0 and github.com/jackc/pgx/v5 from v5.8.0 to v5.9.0, and update the Go toolchain directive to go1.26.4 (or the project's Go version to 1.26.4) to pick up standard-library fixes; then run go get golang.org/x/net@v0.55.0 and go get github.com/jackc/pgx/v5@v5.9.0 (or edit go.mod and run go mod tidy) and re-run tests/build to ensure no breakage.
🧹 Nitpick comments (2)
Dockerfile.rss_cron (2)
20-22: ⚡ Quick winコンテナが root ユーザーで実行されます。
セキュリティのベストプラクティスとして、コンテナは非特権ユーザーで実行すべきです。現在のイメージは root ユーザーで実行されるため、コンテナが侵害された場合の影響範囲が広がります。
🛡️ 修正案: 非特権ユーザーを追加
FROM alpine:3.24.0 WORKDIR /root/ +RUN addgroup -g 1000 appuser && \ + adduser -D -u 1000 -G appuser appuser + RUN apk update && apk add --no-cache \ opus \ opus-dev \ opusfile \ opusfile-dev \ ffmpeg ENV PKG_CONFIG_PATH=/root/.local/lib/pkgconfig ENV LD_LIBRARY_PATH=/root/.local/lib/ COPY --from=builder /root/.local/ /root/.local/ RUN chmod -R 755 /root/.local +WORKDIR /home/appuser COPY --from=builder /app/src/main . -RUN chmod 755 ./main +RUN chown appuser:appuser ./main && chmod 755 ./main +USER appuser CMD ["/root/main"]注: CMD のパスも
/home/appuser/mainに変更する必要があります。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Dockerfile.rss_cron` around lines 20 - 22, コンテナが root で実行されているので、Dockerfile のイメージ設定を非特権ユーザーで動くように修正してください: ベースの WORKDIR を /home/appuser に変更し、Dockerfile 内でユーザー appuser を作成(例: group/user 作成と HOME 設定)、該当ワークディレクトリとバイナリに対して所有権を chown し、最後に USER appuser を追加してコンテナを非 root で実行するようにし、合わせて CMD のパスを /home/appuser/main に更新してください(命名参照: WORKDIR, CMD, USER, appuser)。Source: Linters/SAST tools
35-36: 💤 Low value実行権限が過剰です。
chmod 777は書き込み権限を全ユーザーに付与しますが、実行ファイルには不要です。chmod 755で十分です。♻️ 修正案
-RUN chmod 777 ./main +RUN chmod 755 ./main🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Dockerfile.rss_cron` around lines 35 - 36, 実行バイナリの権限設定が過剰です:現在の RUN chmod 777 ./main(直後の COPY --from=builder /app/src/main . にある実行ファイル)を実行ファイルに必要な最小権限に下げるよう修正してください。具体的には chmod 777 を chmod 755 に変更して、所有者に書き込みを残しつつグループ/その他には実行・読み取りのみ与えるようにしてください。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/docker-tag.yaml:
- Around line 28-45: The rss-cron image is built without passing the --rss-cron
flag to scripts/_build.sh, so Dockerfile.rss_cron ends up embedding the bot
binary; update Dockerfile.rss_cron to invoke ../scripts/_build.sh with the
--rss-cron argument (ensure the RUN line passes "--rss-cron"), and verify
scripts/_build.sh still recognizes that flag and sets TARGET appropriately (the
scripts/_build.sh entry handling --rss-cron and the Dockerfile.rss_cron RUN
invocation are the symbols to change).
In `@Dockerfile.main`:
- Line 19: The RUN instruction "RUN apk add build-base cmake ninja zip pkgconfig
perl nasm" leaves APK cache in the image; update that command to include the
--no-cache flag (i.e., "apk add --no-cache ...") so the package cache is not
stored in the layer, matching the existing pattern used earlier in the
Dockerfile.
- Line 33: Dockerfile のベースイメージ指定 "FROM alpine:3.24.0" は存在しないタグになっているため、実在する
Alpine のタグに置き換えてください(例: alpine:3.18 or alpine:latest); 変更後にローカル/CI 環境で docker
pull <タグ> または docker manifest inspect <タグ> を実行してタグが有効であることを確認し、Dockerfile の
"FROM alpine:3.24.0" 行をその有効なタグに更新してください。
- Line 3: Replace the non-existent base image tag "golang:1.26.4-alpine3.24" in
the Dockerfile's FROM instruction with a real, published tag (e.g.,
"golang:1.26.4-alpine" or another alpine variant confirmed via `docker manifest
inspect`); update the FROM line to use that verified tag so the builder stage
(FROM golang:1.26.4-alpine3.24) pulls successfully.
In `@Dockerfile.rss_cron`:
- Line 18: The Dockerfile currently invokes the build script without the target
flag, causing the default bot binary to be built; update the RUN invocation of
../scripts/_build.sh to pass the --rss-cron flag so the script builds the
rss_cron target (refer to the _build.sh script and the --rss-cron flag).
- Around line 30-33: Dockerfile の rss_cron イメージでビルダーステージに存在しない /root/.local
を参照している ENV PKG_CONFIG_PATH=/root/.local/lib/pkgconfig、ENV
LD_LIBRARY_PATH=/root/.local/lib/、COPY --from=builder /root/.local/
/root/.local/、RUN chmod -R 755 /root/.local
の各命令は不要なのでこれらの行を削除してビルド失敗や空ディレクトリのコピーを防いでください(rss_cron 用には /root/.local
を作成・利用していないため、該当する ENV/COPY/CHMOD 行を取り除くだけで問題ありません)。
- Around line 23-28: The Dockerfile's apk add includes audio packages (opus,
opus-dev, opusfile, opusfile-dev, ffmpeg) that are only needed by the Discord
voice code (voice/player.go) but not by rss_cron (rss_cron/main.go); remove
those packages from the RUN apk add line so the rss_cron image doesn't carry
unnecessary binaries and size/attack-surface. Locate the RUN apk update && apk
add --no-cache block and delete opus, opus-dev, opusfile, opusfile-dev and
ffmpeg from that list, then rebuild and verify rss_cron/main.go still builds
without audio deps.
In `@src/cmd/rss_cron/main.go`:
- Around line 111-146: The loop that builds targetItems incorrectly dereferences
rssSetting.LastItemTitleDescriptionHash and collects only the matching item; fix
by treating LastItemTitleDescriptionHash as nullable, iterating feed.Items from
newest to oldest and collecting each item into targetItems until you encounter a
computed hash equal to the saved hash (stop when matched) so that first-run (nil
saved hash) collects all items; keep using the existing hash computation
(base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", item.Title,
item.Description)))) and slices.Reverse(targetItems) so older-to-newer order is
preserved; after successfully sending messages via client.Rest.CreateMessage,
persist the newest item's hash into rssSetting.LastItemTitleDescriptionHash and
set rssSetting.IsFailed=false (and only mark failure on send error) so state
advances correctly.
- Around line 88-100: When fp.ParseURL(url) returns an error, you currently mark
rssSetting.IsFailed and call repo.Update(rssSetting) but then continue to use
feed (e.g., feed.Title and feed.Items) causing a panic; after successfully
updating the failed rssSetting you must skip further processing for that item
(i.e., continue the loop). Locate the ParseURL error branch around
fp.ParseURL(url), rssSetting.IsFailed and repo.Update and add a control flow
break (continue) after the update so no code references feed when parse failed.
In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 80-95: responseEmbed の成功メッセージが TTS 用の文言になっているため、discord.Embed
を作成している箇所(変数 responseEmbed、discord.Embed の Title/Description フィールド)を修正して RSS
購読完了を正しく案内する文言に置き換えてください(例: Title を「RSS購読を開始しました」、Description
を「指定されたフィードの購読を開始しました」等)。CreateFollowupMessage /
discord.NewMessageCreate().WithEmbeds の呼び出しはそのまま使い、Footer や Timestamp は維持してください。
- Around line 70-78: The RSSSetting being saved lacks ChannelID and ignores DB
errors; update the logic around repository.NewGuildRepository/
guildRepo.GetOrCreate and repository.NewRSSSettingRepository/ rssRepo.Create to
(1) pass and persist the current channel ID into the model.RSSSetting.ChannelID
field, and (2) check and handle returned errors from GetOrCreate and Create (and
any DB ops via ctx.DB), ensuring that if any of these calls fail you do not
return a success response. Locate uses of GetOrCreate, Create, and the
RSSSetting struct to add ChannelID and propagate/handle errors appropriately so
cron code (snowflake.MustParse(rssSetting.ChannelID)) receives a valid saved
ChannelID.
In `@src/internal/bot/handlers/interaction/registry.go`:
- Around line 68-70: The "/rss" route currently only applies
DeferReplyMiddleware and has no execution handler, so the SlashCommand
registered in LoadRssCommandContext() never gets invoked; update the route
registration in registry.go to attach the actual handler by calling
rss.Subscribe(ctxData) (or the appropriate Subscribe handler function) inside
r.Route("/rss", ...) so the SlashCommand has an execution path while keeping
DeferReplyMiddleware applied.
---
Outside diff comments:
In `@src/go.mod`:
- Line 3: Update the Go version to be consistent between src/go.mod and your
Dockerfiles: change the module directive "go 1.24.4" in src/go.mod to match the
Docker images (or update the Dockerfiles to match the module), e.g., set
src/go.mod to "go 1.26.4" if you keep golang:1.26.4-alpine3.24 in
Dockerfile.main and Dockerfile.rss_cron; ensure the version string in the go
directive exactly matches the intended toolchain so builds inside Docker and
local `go` behave identically.
- Around line 20-46: The go.mod contains indirect dependencies with known
vulnerabilities; update the versions and toolchain: bump golang.org/x/net from
v0.49.0 to v0.55.0 and github.com/jackc/pgx/v5 from v5.8.0 to v5.9.0, and update
the Go toolchain directive to go1.26.4 (or the project's Go version to 1.26.4)
to pick up standard-library fixes; then run go get golang.org/x/net@v0.55.0 and
go get github.com/jackc/pgx/v5@v5.9.0 (or edit go.mod and run go mod tidy) and
re-run tests/build to ensure no breakage.
---
Nitpick comments:
In `@Dockerfile.rss_cron`:
- Around line 20-22: コンテナが root で実行されているので、Dockerfile
のイメージ設定を非特権ユーザーで動くように修正してください: ベースの WORKDIR を /home/appuser に変更し、Dockerfile
内でユーザー appuser を作成(例: group/user 作成と HOME 設定)、該当ワークディレクトリとバイナリに対して所有権を chown
し、最後に USER appuser を追加してコンテナを非 root で実行するようにし、合わせて CMD のパスを /home/appuser/main
に更新してください(命名参照: WORKDIR, CMD, USER, appuser)。
- Around line 35-36: 実行バイナリの権限設定が過剰です:現在の RUN chmod 777 ./main(直後の COPY
--from=builder /app/src/main . にある実行ファイル)を実行ファイルに必要な最小権限に下げるよう修正してください。具体的には
chmod 777 を chmod 755 に変更して、所有者に書き込みを残しつつグループ/その他には実行・読み取りのみ与えるようにしてください。
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 01912ca8-56f4-456a-89ed-411fffa004cc
⛔ Files ignored due to path filters (1)
src/go.sumis excluded by!**/*.sum
📒 Files selected for processing (11)
.github/workflows/docker-tag.yamlDockerfile.mainDockerfile.rss_cronscripts/_build.shsrc/cmd/rss_cron/main.gosrc/go.modsrc/internal/bot/handlers/interaction/command/general/rss.gosrc/internal/bot/handlers/interaction/command/general/rss/subscribe.gosrc/internal/bot/handlers/interaction/registry.gosrc/internal/model/rss_setting.gosrc/internal/repository/guild.go
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
…cribe.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/internal/bot/handlers/interaction/command/general/rss/subscribe.go (1)
126-146:⚠️ Potential issue | 🟠 Major | ⚡ Quick win成功レスポンスが公開メッセージになっており、購読 URL をチャンネルに漏らします。
このルートは
DeferReplyMiddleware(ctxData, true, false)でエフェメラル応答にしているのに、成功時だけWithEphemeral(false)を明示してURLフィールドも返しています。確認メッセージはエフェメラルに統一してください。PR objective では確認メッセージをエフェメラルで返す要件です。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go` around lines 126 - 146, The success response is being sent as a public message and leaks the subscription URL; change the follow-up create call to send the embed ephemerally by replacing the explicit WithEphemeral(false) on the discord message builder used in the CreateFollowupMessage call with WithEphemeral(true) (or remove the explicit flag so it inherits DeferReplyMiddleware(ctxData, true, false)), keeping the responseEmbed (including the URL field) and the CreateFollowupMessage invocation unchanged otherwise so the confirmation remains ephemeral.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 97-108: feed.Items[0] will panic on empty feeds and the current
sort comparator mishandles nil PublishedParsed and stable ties; instead,
explicitly check for zero-length feed.Items and return/handle accordingly, then
perform a single-pass scan to pick the latest item (compare
PublishedParsed.UnixNano when both non-nil, treat nil as older, and fall back to
a deterministic tie-breaker like original index or non-empty Title/Description)
and compute the hash from that chosen item (the code around sort.Slice,
feed.Items, PublishedParsed, and the hash assignment should be updated).
- Around line 73-76: The code currently calls fp.ParseURL(url) and persists url
into RSSSetting without validation, enabling SSRF; before any network fetch or
persisting in Subscribe handler (and similarly in rss_cron paths referenced at
lines 116-121), validate the input: parse the URL and require scheme == "http"
or "https", resolve the host with net.LookupIP (or equivalent) and reject any
resolved IPs that are loopback, link-local, multicast or private
(RFC1918/AF_INET6 unique local) or unspecified; only after the URL passes that
whitelist may you call gofeed.NewParser().ParseURL(url) and save to RSSSetting;
apply the same validation function for rss_cron re-fetch to prevent saved
entries from causing SSRF later.
---
Outside diff comments:
In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 126-146: The success response is being sent as a public message
and leaks the subscription URL; change the follow-up create call to send the
embed ephemerally by replacing the explicit WithEphemeral(false) on the discord
message builder used in the CreateFollowupMessage call with WithEphemeral(true)
(or remove the explicit flag so it inherits DeferReplyMiddleware(ctxData, true,
false)), keeping the responseEmbed (including the URL field) and the
CreateFollowupMessage invocation unchanged otherwise so the confirmation remains
ephemeral.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 75a73f9f-7dc6-4a21-9d2e-9cf3e92727e3
📒 Files selected for processing (5)
Dockerfile.mainDockerfile.rss_cronsrc/cmd/rss_cron/main.gosrc/internal/bot/handlers/interaction/command/general/rss/subscribe.gosrc/internal/bot/handlers/interaction/registry.go
🚧 Files skipped from review as they are similar to previous changes (2)
- Dockerfile.main
- src/cmd/rss_cron/main.go
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/cmd/rss_cron/main.go (3)
149-153:⚠️ Potential issue | 🟠 MajorRSS コンテンツからのメンション機能を無効化してください。
itemTitle/itemDescriptionは外部 RSS 由来なので、@everyoneや role mention を含むフィードを購読すると bot 権限で通知を飛ばせます。discord.AllowedMentionsを設定して、すべてのメンション種別を無効化してください:message := fmt.Sprintf( "# %s に新しい記事が追加されました!\n## %s\n%s\nURL: %s", *feedTitle, itemTitle, itemDescription, itemLink, ) _, err := client.Rest.CreateMessage( channelID, discord.NewMessageCreate(). WithContent(message). SetAllowedMentions(&discord.AllowedMentions{Parse: []discord.AllowedMentionType{}}), )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cmd/rss_cron/main.go` around lines 149 - 153, The Discord message creation in the fmt.Sprintf block is vulnerable to mention injection from external RSS content because itemTitle and itemDescription could contain `@everyone` or role mentions. To fix this, modify the client.Rest.CreateMessage call to include SetAllowedMentions with an empty Parse array on the discord.NewMessageCreate() builder. This will disable all mention parsing (Parse field set to an empty slice of discord.AllowedMentionType) so that any mentions in the RSS feed content will be rendered as plain text instead of being executed with bot permissions.
66-73:⚠️ Potential issue | 🟠 Major
OpenGateway呼び出し直後にmainが終了して、RSS処理が実行されません。DisGo v0.19.3 の
OpenGateway(ctx)はゲートウェイ接続後に戻ります (ブロック継続はしません)。そのため Line 73 の直後にmain()が終了し、defer client.Close(...)でクライアントが閉じられ、RSS取得・投稿処理は実行されないか途中で中断します。cron として1回限りならReady完了を待ち、常駐 Bot なら signal 待機 (<-ctx.Done()など) を追加してください。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cmd/rss_cron/main.go` around lines 66 - 73, The `OpenGateway` call in DisGo v0.19.3 returns immediately after connecting to the gateway without blocking, causing the main function to exit right after the log statement on line 73. This triggers the `defer client.Close(context.TODO())` cleanup, terminating the client before any RSS processing occurs. After the successful `OpenGateway` call and log message, add logic to keep the program running: for a cron job that runs once, wait for the client's Ready event to complete; for a resident Bot, add a blocking call like waiting on a context done channel or signal handler to prevent the main function from exiting until the program should terminate.
103-110:⚠️ Potential issue | 🟠 Major
sort.Sliceの比較関数を strict に修正してください。行 107 の
>=は同一時刻でless(i,j)とless(j,i)が両方 true になり、strict weak ordering が破綻します。subscribe.goのSliceStable+Afterパターンに統一することで、初回保存ハッシュと cron 側の判定一致も確保されます。- sort.Slice(feed.Items, func(i, j int) bool { - prev := feed.Items[i] - next := feed.Items[j] - if prev.PublishedParsed != nil && next.PublishedParsed != nil { - return prev.PublishedParsed.UnixNano() >= next.PublishedParsed.UnixNano() - } - return false + sort.SliceStable(feed.Items, func(i, j int) bool { + a := feed.Items[i].PublishedParsed + b := feed.Items[j].PublishedParsed + + switch { + case a == nil && b == nil: + return false + case a == nil: + return false + case b == nil: + return true + default: + return a.After(*b) + } })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cmd/rss_cron/main.go` around lines 103 - 110, The comparison function in the sort.Slice call for feed.Items violates strict weak ordering because the `>=` operator on line 107 allows both less(i,j) and less(j,i) to return true when PublishedParsed times are equal. Replace sort.Slice with sort.SliceStable and change the `>=` comparison to `>` to enforce strict ordering. Alternatively, align this implementation with the slicing and comparison pattern used in subscribe.go to ensure consistency between initial hash validation and cron-side processing.src/internal/bot/handlers/interaction/command/general/rss/subscribe.go (1)
111-117:⚠️ Potential issue | 🔴 CriticalRSSSetting 作成時に
IDフィールドを設定してください。
RSSSettingモデルはID stringを primary key として定義していますが、この作成時に ID が設定されていません。コードベース内に BeforeCreate フックや ID 自動生成メカニズムが存在しないため、ID はデフォルトの空文字列のまま挿入されます。その結果、最初の購読作成は成功しますが、2件目以降の作成は primary key 重複エラーで失敗します。修正例
+import "github.com/google/uuid" - if err := rssRepo.Create(&model.RSSSetting{ + if err := rssRepo.Create(&model.RSSSetting{ + ID: uuid.New().String(), GuildID: guildID.String(), ChannelID: e.Channel().ID().String(), URL: url,🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go` around lines 111 - 117, The RSSSetting model uses an ID string field as its primary key, but when creating the RSSSetting object in the rssRepo.Create call, the ID field is not being populated. Since there is no automatic ID generation mechanism in place, all insertions default to an empty string for the ID, causing subsequent subscribe attempts to fail with primary key conflicts. Generate a unique ID (such as using a UUID) and assign it to the ID field of the RSSSetting struct before passing it to rssRepo.Create.
♻️ Duplicate comments (1)
src/cmd/rss_cron/main.go (1)
153-164:⚠️ Potential issue | 🟠 Major | ⚡ Quick win送信失敗時は最新ハッシュを進めないでください。
Line 154-156 で送信エラーをログだけにしているため、その後 Line 160-164 で
LastItemTitleDescriptionHashとIsFailed=falseを保存すると、未投稿の記事が次回以降スキップされます。送信エラー時は失敗状態を保存してcontinueしてください。修正案
client := e.Client() + sendFailed := false for _, item := range targetItems { @@ _, err := client.Rest.CreateMessage(channelID, discord.NewMessageCreate().WithContent(message)) if err != nil { log.Print("Message create error:", err) + sendFailed = true + break } } + + if sendFailed { + rssSetting.IsFailed = true + if err := repo.Update(rssSetting); err != nil { + log.Print("Update Record Failed", err) + } + continue + } // 送信完了後に最新ハッシュを保存(feed.Items[0] = 最新記事)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cmd/rss_cron/main.go` around lines 153 - 164, The issue is that when client.Rest.CreateMessage fails to send the Discord message, the error is only logged but execution continues to update LastItemTitleDescriptionHash and set IsFailed to false, causing unposted articles to be skipped in future runs. Fix this by modifying the error handling block where client.Rest.CreateMessage fails: instead of just logging the error, set rssSetting.IsFailed to true, call repo.Update to save the failed state, and use continue to skip the subsequent hash update logic that comes after the conditional block.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Dockerfile.rss_cron`:
- Around line 32-36: The binary file is moved from /root/main to
/home/appuser/main on line 32 using the mv command, but the CMD instruction on
line 36 still references the old path /root/main which no longer exists after
the move. Update the CMD instruction to use /home/appuser/main as the execution
path to match where the binary was relocated to, ensuring the container will
execute the correct binary location when it starts.
In `@src/internal/util/rss_fetch.go`:
- Around line 139-154: The privateCIDRs slice in the SSRF filter is missing
critical address ranges that should be blocked for security. Add three
additional CIDR blocks to the privateCIDRs array: the IPv4 unspecified address
range, the IPv6 unspecified address, and the IPv6 multicast range. These should
be inserted into the existing privateCIDRs slice alongside the other CIDR blocks
to ensure that all local and special-purpose addresses that should not be
accessible are explicitly blocked when filtering user-provided URLs.
- Around line 33-61: The http.Transport object created in the DialContext
function is not closing its idle connections after use, which causes file
descriptor leaks when FetchFeed is called multiple times. After closing the
response body with resp.Body.Close(), explicitly call CloseIdleConnections() on
the transport variable to clean up idle connections and release file descriptors
that would otherwise remain held by the Transport.
---
Outside diff comments:
In `@src/cmd/rss_cron/main.go`:
- Around line 149-153: The Discord message creation in the fmt.Sprintf block is
vulnerable to mention injection from external RSS content because itemTitle and
itemDescription could contain `@everyone` or role mentions. To fix this, modify
the client.Rest.CreateMessage call to include SetAllowedMentions with an empty
Parse array on the discord.NewMessageCreate() builder. This will disable all
mention parsing (Parse field set to an empty slice of
discord.AllowedMentionType) so that any mentions in the RSS feed content will be
rendered as plain text instead of being executed with bot permissions.
- Around line 66-73: The `OpenGateway` call in DisGo v0.19.3 returns immediately
after connecting to the gateway without blocking, causing the main function to
exit right after the log statement on line 73. This triggers the `defer
client.Close(context.TODO())` cleanup, terminating the client before any RSS
processing occurs. After the successful `OpenGateway` call and log message, add
logic to keep the program running: for a cron job that runs once, wait for the
client's Ready event to complete; for a resident Bot, add a blocking call like
waiting on a context done channel or signal handler to prevent the main function
from exiting until the program should terminate.
- Around line 103-110: The comparison function in the sort.Slice call for
feed.Items violates strict weak ordering because the `>=` operator on line 107
allows both less(i,j) and less(j,i) to return true when PublishedParsed times
are equal. Replace sort.Slice with sort.SliceStable and change the `>=`
comparison to `>` to enforce strict ordering. Alternatively, align this
implementation with the slicing and comparison pattern used in subscribe.go to
ensure consistency between initial hash validation and cron-side processing.
In `@src/internal/bot/handlers/interaction/command/general/rss/subscribe.go`:
- Around line 111-117: The RSSSetting model uses an ID string field as its
primary key, but when creating the RSSSetting object in the rssRepo.Create call,
the ID field is not being populated. Since there is no automatic ID generation
mechanism in place, all insertions default to an empty string for the ID,
causing subsequent subscribe attempts to fail with primary key conflicts.
Generate a unique ID (such as using a UUID) and assign it to the ID field of the
RSSSetting struct before passing it to rssRepo.Create.
---
Duplicate comments:
In `@src/cmd/rss_cron/main.go`:
- Around line 153-164: The issue is that when client.Rest.CreateMessage fails to
send the Discord message, the error is only logged but execution continues to
update LastItemTitleDescriptionHash and set IsFailed to false, causing unposted
articles to be skipped in future runs. Fix this by modifying the error handling
block where client.Rest.CreateMessage fails: instead of just logging the error,
set rssSetting.IsFailed to true, call repo.Update to save the failed state, and
use continue to skip the subsequent hash update logic that comes after the
conditional block.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9fbdde18-42e9-4403-8e3e-3435e7c1b6bd
📒 Files selected for processing (6)
Dockerfile.mainDockerfile.rss_cronsrc/cmd/rss_cron/main.gosrc/go.modsrc/internal/bot/handlers/interaction/command/general/rss/subscribe.gosrc/internal/util/rss_fetch.go
🚧 Files skipped from review as they are similar to previous changes (2)
- src/go.mod
- Dockerfile.main
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Yuito Akatsuki (Tani Yutaka) <yuito@yuito-it.jp>
Summary by CodeRabbit
リリースノート
/rss/subscribeで登録し、新規記事を自動投稿します)。bot/v*とrss-cron/v*に対応しました。